LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

-------------------------------------- Forwarding_Prototype --------------------------------------------------

ENTITY Test_Forwarding_Engine IS

    PORT(
       
       -- Legit pins
       clr : IN STD_LOGIC;
       clk : IN STD_LOGIC;
       
       -- ForwardingBuffer.vhd
       data_available0, data_available1, data_available2, data_available3 : IN STD_LOGIC;
	   clk_out, clr_out : OUT STD_LOGIC;
       pass_data_out0, pass_data_out1, pass_data_out2, pass_data_out3 : OUT STD_LOGIC;
       IN_RCV0_to_FWD_DATA, IN_RCV1_to_FWD_DATA, IN_RCV2_to_FWD_DATA, IN_RCV3_to_FWD_DATA	: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
	   IN_RCV0_to_FWD_LENGTH, IN_RCV1_to_FWD_LENGTH, IN_RCV2_to_FWD_LENGTH, IN_RCV3_to_FWD_LENGTH  	  : IN STD_LOGIC_VECTOR(11 DOWNTO 0); --MSB is valid bit
	   IN_RCV0_to_FWD_DATA_out, IN_RCV1_to_FWD_DATA_out, IN_RCV2_to_FWD_DATA_out, IN_RCV3_to_FWD_DATA_out : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
       OUT_FWD_to_RCV0_LENGTH_ACK, OUT_FWD_to_RCV1_LENGTH_ACK, OUT_FWD_to_RCV2_LENGTH_ACK, OUT_FWD_to_RCV3_LENGTH_ACK  : OUT STD_LOGIC;
	   OUT_FWD_to_RCV0_FRAME_ACK, OUT_FWD_to_RCV1_FRAME_ACK, OUT_FWD_to_RCV2_FRAME_ACK, OUT_FWD_to_RCV3_FRAME_ACK	  : OUT STD_LOGIC;
       count_out0, count_out1, count_out2, count_out3 : OUT STD_LOGIC_VECTOR(11 DOWNTO 0);
       srcAddress0Validout, srcAddress1Validout, srcAddress2Validout, srcAddress3Validout : OUT STD_LOGIC;
       desAddress0Validout, desAddress1Validout, desAddress2Validout, desAddress3Validout : OUT STD_LOGIC;
       packetType0, packetType1, packetType2, packetType3 : OUT STD_LOGIC;
       sendingsrcAddress0out, sendingdesAddress0out, sendingsrcAddress1out, sendingdesAddress1out, sendingsrcAddress2out, sendingdesAddress2out, sendingsrcAddress3out, sendingdesAddress3out : OUT STD_LOGIC;
       packet_size_comparator_out0, packet_size_comparator_out1, packet_size_comparator_out2, packet_size_comparator_out3 : OUT STD_LOGIC;
	   portChoiceout : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
	   portReadyout  : OUT STD_LOGIC;
	   OMX_to_ARB_Done_out : OUT STD_LOGIC;
   
	   TBL_to_FWD_ACK : IN STD_LOGIC;
	   TBL_to_FWD_ACK_out: OUT STD_LOGIC;
	   TBL_to_FWD_Valid : IN STD_LOGIC;
	   TBL_to_FWD_Valid_out : OUT STD_LOGIC;
	   TBL_to_FWD_Port : IN STD_LOGIC_VECTOR(2 DOWNTO 0);
	   TBL_to_FWD_Port_out : OUT STD_LOGIC_VECTOR(2 DOWNTO 0);
	   FWD_to_XMT0_ACK, FWD_to_XMT1_ACK, FWD_to_XMT2_ACK, FWD_to_XMT3_ACK : OUT STD_LOGIC;
	   XMT0_to_FWD_spaceavailable, XMT1_to_FWD_spaceavailable, XMT2_to_FWD_spaceavailable,XMT3_to_FWD_spaceavailable : IN STD_LOGIC_VECTOR(10 DOWNTO 0);
       FWD_to_TBL_desAddress, FWD_to_TBL_srcAddress : OUT STD_LOGIC_VECTOR(47 DOWNTO 0);
       FWD_to_TBL_srcPort : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
       FWD_to_TBL_ACK :OUT STD_LOGIC;
	   FWD_to_XMT0_DONE, FWD_to_XMT1_DONE, FWD_to_XMT2_DONE, FWD_to_XMT3_DONE : OUT STD_LOGIC;
	   FWD_to_XMT0_LENGTH, FWD_to_XMT1_LENGTH, FWD_to_XMT2_LENGTH, FWD_to_XMT3_LENGTH : OUT STD_LOGIC_VECTOR(11 DOWNTO 0);
	   FWD_to_XMT0_DATA, FWD_to_XMT1_DATA, FWD_to_XMT2_DATA, FWD_to_XMT3_DATA : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)

       
       );
       
END Test_Forwarding_Engine;

ARCHITECTURE test_fwd_engine_arch OF Test_Forwarding_Engine IS
   
-------------------------------------- Components ----------------------------------------------- 

--------------------------------------- Buffer  ------------------------------------------------------

COMPONENT ForwardingBuffer IS
   PORT(
       clr : IN STD_LOGIC;
       clk : IN STD_LOGIC;
       data_available : IN STD_LOGIC;
       pass_data	:	IN	STD_LOGIC;
       IN_RCV_to_FWD_DATA	  	  : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
	   IN_RCV_to_FWD_LENGTH  	  : IN STD_LOGIC_VECTOR(11 DOWNTO 0);
       OUT_FWD_to_RCV_LENGTH_ACK  : OUT STD_LOGIC;
	   OUT_FWD_to_RCV_FRAME_ACK	  : OUT STD_LOGIC;
       data_out : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
       count_out : OUT STD_LOGIC_VECTOR(11 DOWNTO 0);
       srcAddressValid : OUT STD_LOGIC;
       desAddressValid : OUT STD_LOGIC;
       packetType : OUT STD_LOGIC;
       srcAddress : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
       desAddress : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
       sendingsrcAddress, sendingdesAddress : OUT STD_LOGIC;
       packet_size_comparator_out : OUT STD_LOGIC;
       bufferSize : OUT STD_LOGIC_VECTOR(10 DOWNTO 0);
       bufferDone : OUT STD_LOGIC;
       bufferAlmostDone : OUT STD_LOGIC;
       IPv4_frame_count, VLAN_frame_count	:	OUT STD_LOGIC_VECTOR(11 DOWNTO 0)

       );
END COMPONENT;

-------------------------------------- Arbiter  ------------------------------------------------------

COMPONENT Arbiter IS
   PORT(
       clock : IN STD_LOGIC;
       asreset : IN STD_LOGIC;
       tableheardarbiter : IN STD_LOGIC;
       OMX_to_ARB_Done : IN STD_LOGIC;
	   srcAddressValid0, srcAddressValid1, srcAddressValid2, srcAddressValid3 : IN STD_LOGIC;
	   desAddressValid0, desAddressValid1, desAddressValid2, desAddressValid3 : IN STD_LOGIC;
	   portChoice : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
	   portReady : OUT STD_LOGIC -- Are any ports ready?;
       );
END COMPONENT;

-------------------------------------- AddressMUX   ------------------------------------------------------

COMPONENT addbuff3 IS
   PORT(
       clk, reset :  IN STD_LOGIC;     -- clk
       TBL_to_FWD_ACK : IN STD_LOGIC;
   	   OMX_to_ARB_Done : IN STD_LOGIC;
       portChoice : IN STD_LOGIC_VECTOR(1 DOWNTO 0); -- portChoice
       portvalid: IN STD_LOGIC; -- portReady
	   des_mux0, des_mux1,des_mux2,des_mux3 : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- desAddress0
	   src_mux0, src_mux1,src_mux2,src_mux3: IN STD_LOGIC_VECTOR(7 DOWNTO 0);  -- srcAddress0
	   WE_READY: OUT STD_LOGIC; -- ACK to table indicating that table can start reading the data
	   src_ready0, src_ready1, src_ready2, src_ready3 : IN STD_LOGIC; -- sendingsrcAddress0
	   des_ready0, des_ready1, des_ready2, des_ready3 : IN STD_LOGIC; -- sendingdesAddress0
	   srcPort : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);	  -- FWD_to_TBL_srcPort
	   srcAddress : OUT STD_LOGIC_VECTOR(47 DOWNTO 0);-- FWD_to_TBL_srcAddress
	   desAddress : OUT STD_LOGIC_VECTOR(47 DOWNTO 0) -- FWD_to_TBL_desAddress
       );
END COMPONENT;

-------------------------------------- OutMUX   ------------------------------------------------------

COMPONENT OutMUX IS
   PORT(
		clk, reset : IN STD_LOGIC;
		buffer0_data, buffer1_data, buffer2_data, buffer3_data : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
		buffer0_size, buffer1_size, buffer2_size, buffer3_size : IN STD_LOGIC_VECTOR(10 DOWNTO 0);
		buffer0_done, buffer1_done, buffer2_done, buffer3_done : IN STD_LOGIC;
	    srcAddressValid0, srcAddressValid1, srcAddressValid2, srcAddressValid3 : IN STD_LOGIC;
	    desAddressValid0, desAddressValid1, desAddressValid2, desAddressValid3 : IN STD_LOGIC;
	    TBL_to_FWD_ACK : IN STD_LOGIC;
		TBL_to_FWD_Valid : IN STD_LOGIC;
		ARB_to_OMX_Port : IN STD_LOGIC_VECTOR(1 DOWNTO 0);
		ARB_to_OMX_Valid : IN STD_LOGIC;
		TBL_to_FWD_Port : IN STD_LOGIC_VECTOR(2 DOWNTO 0);		
		XMT0_size, XMT1_size, XMT2_size, XMT3_size : IN STD_LOGIC_VECTOR(10 DOWNTO 0);
		buffer0_request, buffer1_request, buffer2_request, buffer3_request : OUT STD_LOGIC;
		FWD_to_XMT0_ACK, FWD_to_XMT1_ACK, FWD_to_XMT2_ACK, FWD_to_XMT3_ACK : OUT STD_LOGIC;
		FWD_to_XMT0_Data, FWD_to_XMT1_Data, FWD_to_XMT2_Data, FWD_to_XMT3_Data : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
		FWD_to_XMT0_Size, FWD_to_XMT1_Size, FWD_to_XMT2_Size, FWD_to_XMT3_Size : OUT STD_LOGIC_VECTOR(11 DOWNTO 0);
		FWD_to_XMT0_Done, FWD_to_XMT1_Done, FWD_to_XMT2_Done, FWD_to_XMT3_Done : OUT STD_LOGIC;
		bufferAlmostDone0, bufferAlmostDone1, bufferAlmostDone2, bufferAlmostDone3 : IN STD_LOGIC;
		OMX_to_ARB_Done  : OUT STD_LOGIC
       );
END COMPONENT;




-------------------------------------- Signals  ------------------------------------------------------

-- COUNTERS
SIGNAL CountA, CountB, CountC : STD_LOGIC;
SIGNAL CounterA : STD_LOGIC_VECTOR(16 DOWNTO 0);
SIGNAL CounterB : STD_LOGIC_VECTOR(16 DOWNTO 0);
SIGNAL CounterC : STD_LOGIC_VECTOR(16 DOWNTO 0);

-- BUFFER
SIGNAL srcAddress0, srcAddress1, srcAddress2, srcAddress3 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL desAddress0, desAddress1, desAddress2, desAddress3 : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL sendingsrcAddress0, sendingdesAddress0, sendingsrcAddress1, sendingdesAddress1, sendingsrcAddress2, sendingdesAddress2, sendingsrcAddress3, sendingdesAddress3 : STD_LOGIC;
SIGNAL bufferSize0, bufferSize1, bufferSize2, bufferSize3 : STD_LOGIC_VECTOR(10 DOWNTO 0);
SIGNAL bufferDone0, bufferDone1, bufferDone2, bufferDone3 : STD_LOGIC;
SIGNAL data_out0, data_out1, data_out2, data_out3 : STD_LOGIC_VECTOR(7 DOWNTO 0); 
--SIGNAL count_out0, count_out1, count_out2, count_out3	:	STD_LOGIC_VECTOR(11 DOWNTO 0);
SIGNAL pass_data0, pass_data1, pass_data2, pass_data3	:	STD_LOGIC;
SIGNAL OMX_to_ARB_Done : STD_LOGIC;
SIGNAL BAD0, BAD1, BAD2, BAD3 : STD_LOGIC;

-- ARBITER
SIGNAL srcAddress0Valid, srcAddress1Valid, srcAddress2Valid, srcAddress3Valid : STD_LOGIC;
SIGNAL desAddress0Valid, desAddress1Valid, desAddress2Valid, desAddress3Valid : STD_LOGIC;
SIGNAL portChoice : STD_LOGIC_VECTOR(1 DOWNTO 0);
SIGNAL portReady  : STD_LOGIC;

SIGNAL IPv4_frame_count_out0, VLAN_frame_count_out0, IPv4_frame_count_out1, VLAN_frame_count_out1, IPv4_frame_count_out2, VLAN_frame_count_out2, IPv4_frame_count_out3, VLAN_frame_count_out3 	:	STD_LOGIC_VECTOR(11 DOWNTO 0);


BEGIN

OMX_to_ARB_Done_out <= OMX_to_ARB_Done;

srcAddress0Validout <= srcAddress0Valid;
srcAddress1Validout <= srcAddress1Valid;
srcAddress2Validout <= srcAddress2Valid;
srcAddress3Validout <= srcAddress3Valid;

desAddress0Validout <= desAddress0Valid;
desAddress1Validout <= desAddress1Valid;
desAddress2Validout <= desAddress2Valid;
desAddress3Validout <= desAddress3Valid;

portChoiceout <= portChoice;
portReadyout  <= portReady;

--srcAddress0out <= srcAddress0;
--srcAddress1out <= srcAddress1;
--srcAddress2out <= srcAddress2; 
--srcAddress3out <= srcAddress3;
--desAddress0out <= desAddress0;
--desAddress1out <= desAddress1;
--desAddress2out <= desAddress2;
--desAddress3out <= desAddress3;

sendingsrcAddress0out <= sendingsrcAddress0;
sendingdesAddress0out <= sendingdesAddress0; 
sendingsrcAddress1out <= sendingsrcAddress1;
sendingdesAddress1out <= sendingdesAddress1;
sendingsrcAddress2out <= sendingsrcAddress2; 
sendingdesAddress2out <= sendingdesAddress2;
sendingsrcAddress3out <= sendingsrcAddress3;
sendingdesAddress3out <= sendingdesAddress3;

TBL_to_FWD_Port_out <= TBL_to_FWD_Port;
TBL_to_FWD_Valid_out <= TBL_to_FWD_Valid;
TBL_to_FWD_ACK_out <= TBL_to_FWD_ACK;

----------------------------------------------- Buffering --------------------------------------------- 
       
pass_data_out0 <= pass_data0;
pass_data_out1 <= pass_data1;
pass_data_out2 <= pass_data2;
pass_data_out3 <= pass_data3;

clk_out <= clk;
clr_out <= clr;

IN_RCV0_to_FWD_DATA_out <=  IN_RCV0_to_FWD_DATA;
IN_RCV1_to_FWD_DATA_out <=  IN_RCV1_to_FWD_DATA;
IN_RCV2_to_FWD_DATA_out <=  IN_RCV2_to_FWD_DATA;
IN_RCV3_to_FWD_DATA_out <=  IN_RCV3_to_FWD_DATA;
       
Buffer0: ForwardingBuffer PORT MAP (clr, clk, data_available0, pass_data0, IN_RCV0_to_FWD_DATA, IN_RCV0_to_FWD_LENGTH, OUT_FWD_to_RCV0_LENGTH_ACK,
OUT_FWD_to_RCV0_FRAME_ACK, data_out0, count_out0, srcAddress0Valid, desAddress0Valid, packetType0, srcAddress0, desAddress0, sendingsrcAddress0, sendingdesAddress0,
packet_size_comparator_out0, bufferSize0, bufferDone0, BAD0, IPv4_frame_count_out0, VLAN_frame_count_out0);

Buffer1: ForwardingBuffer PORT MAP (clr, clk, data_available1, pass_data1, IN_RCV1_to_FWD_DATA, IN_RCV1_to_FWD_LENGTH, OUT_FWD_to_RCV1_LENGTH_ACK,
OUT_FWD_to_RCV1_FRAME_ACK, data_out1, count_out1, srcAddress1Valid, desAddress1Valid, packetType1, srcAddress1, desAddress1, sendingsrcAddress1, sendingdesAddress1,
packet_size_comparator_out1, bufferSize1, bufferDone1, BAD1, IPv4_frame_count_out1, VLAN_frame_count_out1);

Buffer2: ForwardingBuffer PORT MAP (clr, clk, data_available2, pass_data2, IN_RCV2_to_FWD_DATA, IN_RCV2_to_FWD_LENGTH, OUT_FWD_to_RCV2_LENGTH_ACK,
OUT_FWD_to_RCV2_FRAME_ACK, data_out2, count_out2, srcAddress2Valid, desAddress2Valid, packetType2, srcAddress2, desAddress2, sendingsrcAddress2, sendingdesAddress2,
packet_size_comparator_out2, bufferSize2, bufferDone2, BAD2, IPv4_frame_count_out2, VLAN_frame_count_out2);

Buffer3: ForwardingBuffer PORT MAP (clr, clk, data_available3, pass_data3, IN_RCV3_to_FWD_DATA, IN_RCV3_to_FWD_LENGTH, OUT_FWD_to_RCV3_LENGTH_ACK,
OUT_FWD_to_RCV3_FRAME_ACK, data_out3, count_out3, srcAddress3Valid, desAddress3Valid, packetType3, srcAddress3, desAddress3, sendingsrcAddress3, sendingdesAddress3,
packet_size_comparator_out3, bufferSize3, bufferDone3, BAD3, IPv4_frame_count_out3, VLAN_frame_count_out3);

--
-------------------------------------------------  Arbiter  ---------------------------------------------
--
---- Asynchronously choose between four inputs. (Just straight-up logic.)
--
---- Is portReady the same as portValid?
---- portValid is an input, portReady is an output. portReady is ready if enough portValids are valid.
Arbitrate: Arbiter PORT MAP (clk, clr, TBL_to_FWD_ACK, OMX_to_ARB_Done, srcAddress0Valid, srcAddress1Valid, srcAddress2Valid, srcAddress3Valid,
desAddress0Valid, desAddress1Valid, desAddress2Valid, desAddress3Valid, portChoice, portReady);
--
----arbiter_debug_portChoice <= portChoice;
--arbiter_debug_portReady <= portReady;
--
--
-------------------------------------------------     ADDBUFF   ---------------------------------------------
--
AddressBuffer: addbuff3 PORT MAP (clk, clr, TBL_to_FWD_ACK, OMX_to_ARB_Done, portChoice, portReady, desAddress0, desAddress1, desAddress2,
desAddress3, srcAddress0, srcAddress1, srcAddress2, srcAddress3, FWD_to_TBL_ACK ,sendingsrcAddress0, sendingsrcAddress1,
sendingsrcAddress2, sendingsrcAddress3, sendingdesAddress0, sendingdesAddress1, sendingdesAddress2, sendingdesAddress3,
FWD_to_TBL_srcPort, FWD_to_TBL_srcAddress, FWD_to_TBL_desAddress);

--
-------------------------------------------------     MUX 2    ---------------------------------------------

OutMUXGo: OutMUX PORT MAP (clk, clr, data_out0, data_out1, data_out2, data_out3, 
bufferSize0, bufferSize1, bufferSize2, bufferSize3, bufferDone0, bufferDone1, bufferDone2, bufferDone3, 
srcAddress0Valid, srcAddress1Valid, srcAddress2Valid, srcAddress3Valid,
desAddress0Valid, desAddress1Valid, desAddress2Valid, desAddress3Valid,
TBL_to_FWD_ACK, TBL_to_FWD_Valid, portChoice, portReady, 
TBL_to_FWD_Port, XMT0_to_FWD_spaceavailable, XMT1_to_FWD_spaceavailable, XMT2_to_FWD_spaceavailable, XMT3_to_FWD_spaceavailable, 
pass_data0, pass_data1, pass_data2, pass_data3, FWD_to_XMT0_ACK, FWD_to_XMT1_ACK, FWD_to_XMT2_ACK, FWD_to_XMT3_ACK, 
FWD_to_XMT0_DATA, FWD_to_XMT1_DATA, FWD_to_XMT2_DATA, FWD_to_XMT3_DATA, FWD_to_XMT0_LENGTH, FWD_to_XMT1_LENGTH, FWD_to_XMT2_LENGTH, FWD_to_XMT3_LENGTH, 
FWD_to_XMT0_DONE, FWD_to_XMT1_DONE, FWD_to_XMT2_DONE, FWD_to_XMT3_DONE, BAD0, BAD1, BAD2, BAD3, OMX_to_ARB_Done);

--
----OutMUX_debug_buffer0_request <= pass_data0;
----OutMUX_debug_buffer1_request <= pass_data1;
----OutMUX_debug_buffer2_request <= pass_data2;
----OutMUX_debug_buffer3_request <= pass_data3;


END test_fwd_engine_arch;